const { Service } = require('egg')
const cheerio = require('cheerio')
const { tableToList, transformArray, getTerm } = require('../utils/tools')

/**
 * 根据输入的成绩字符串判断其状态。
 * @param {string} str 表示成绩的字符串，可以是数字或者文字。
 * @return {Array} 返回一个包含两个元素的数组。第一个元素是输入的成绩字符串，第二个元素是成绩的状态，
 *                  如果成绩是数字，则状态为'已获'（及格）或'已开未获'（不及格）；如果成绩是文字，则状态为'已获'（及格）或'已开未获'（不及格）。
 */
const gradeStatus = (str) => {
  if (/^\d+$/.test(str)) { // 如果输入的是数字
    return [str, (Number(str) >= 60) ? '已获' : '已开未获'] // 判断数字是否及格，及格则返回'已获'，否则返回'已开未获'
  }
  return [str, str === '不及格' ? '已开未获' : '已获'] // 如果输入的是文字，判断是否为'不及格'，是则返回'已开未获'，否则返回'已获'
}

module.exports = class CreditService extends Service {
  /**
   * 学分修读情况
   * @return {Array} *
   */
  async table() {
    // 身份识别信息+学号(获取入学年份),sid-学号
    const Cookie = this.ctx.state.Cookie
    const sid = this.ctx.data.sid
    // 对学号进行处理，得到入学年份
    const year = sid.slice(1, 5)
    // 结果保存容器
    const result = []
    // 访问最初的学生完成情况(体系)页面，获取个人识别关键信息ndzydm属性值,ccs-学生完成情况，fir-first
    const ccsFir = `${this.ctx.state.baseUrl}/jsxsd/xxwcqk/xxwcqk_idxOntx.do`

    // 发送请求，获取网页内容
    const resCcs1 = await this.ctx.curl(ccsFir, {
      method: 'GET',
      headers: {
        Cookie,
        // 'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
      },
      timeout: 10000,
    })
    // 请求状态200检查
    if (resCcs1.status === 200) {
      try {
        // 加载网页内容
        const $ = cheerio.load(resCcs1.data.toString())
        // 从网页内容中寻找到ndzydm属性，获取到其中的value值
        const ndzydm = $('*[name="ndzydm"]').val()

        // 正式访问学生完成情况(体系)页面，获取到汇总表,ccs-学生完成情况
        const resCcs2 = this.ctx.curl(`${this.ctx.state.baseUrl}/jsxsd/xxwcqk/xxwcqkOnkctx.do`, {
          method: 'POST',
          headers: {
            Cookie,
            'Content-Type': 'application/x-www-form-urlencoded',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
          },
          data: {
            ndzydm, // 关键的身份验证码
            jx0301zxjhid: '',
          },
        })

        // 访问培养计划，获取到未修读课程的年份信息，tp-培养计划
        const tpRes = this.ctx.curl(`${this.ctx.state.baseUrl}/jsxsd/pyfa/topyfamx`, {
          method: 'GET',
          headers: {
            Cookie,
            'Content-Type': 'application/x-www-form-urlencoded',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
          },
        })

        // 访问成绩，获取到已修读课程的年份信息
        const sgUrl = `${this.ctx.state.baseUrl}/jsxsd/kscj/cjcx_list`
        const sgRes = this.ctx.curl(sgUrl, {
          method: 'POST',
          data: {
            kksj: '',
            kcxz: '',
            kcmc: '',
            xsfs: 'all',
          },
          headers: {
            Cookie,
            'Content-Type': 'application/x-www-form-urlencoded',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
          },
          timeout: 10000,
        })

        /* 将异步操作完成结果赋值：R1-P1;R2-P2 */
        const [ccs, tp, sg] = await Promise.all([resCcs2, tpRes, sgRes])
        if (ccs.status === 200 && tp.status === 200) {
          // 获取培养计划表格
          const tableTp = tableToList(tp.data.toString(), '#mxh')
          // console.log('tableTp', tableTp)
          // 获取成绩表
          const tableSg = tableToList(sg.data.toString(), '#dataList')
          // console.log('tableSg', tableSg)

          // 从培养计划和成绩中提取课程及其开课时间，成绩优先级大
          const dictCourse = {}

          tableTp.forEach((e, i) => { if (i > 0) { dictCourse[e[3]] = getTerm(year, e[11]) } })
          tableSg.forEach((e, i) => { if (i > 0) dictCourse[e[3]] = e[1] })
          // console.log('dictCourse', dictCourse)

          // 提取学生每个分类的应修和已修分数
          const tableCcs1 = tableToList(ccs.data.toString(), '.Nsb_r_list:first')
          const dictCredit = {}
          tableCcs1.forEach((e, i) => {
            if (e[0] !== '总计' && i !== 0) dictCredit[e[0]] = [e[1], e[2]]
          })
          console.log('dictCredit', dictCredit)

          // 获取学生每个分类下的汇总信息表格
          const tableCcs2 = tableToList(ccs.data.toString(), '.Nsb_r_list:last')
          // console.log('tableCcs2', tableCcs2)

          // 数据清理
          const tableCcs3 = []
          let type = ''
          for (let i = 1; i < tableCcs2.length; i++) {
            if (tableCcs2[i][0] === '') {
              type = ''
              continue
            }
            if (type === '') type = tableCcs2[i][0]
            else {
              if (tableCcs2[i][5] === '修读中') tableCcs2[i][0] = `${type}(${tableCcs2[i][3]})`
              else tableCcs2[i][0] = `${type}(${tableCcs2[i][4]})`
              tableCcs3.push(tableCcs2[i])
            }
          }
          // console.log('tableCcs3', tableCcs3)

          // 数据构造
          const transform = transformArray(tableCcs3, 0, null, (value) => ({
            N: value[0],
            T: dictCourse[value[0]] || '',
            C: value[1],
            G: value[4],
            S: value[4] === '修读中' ? '' : gradeStatus(value[4])[1],
          }))
          // console.log('transform', transform)

          // 整合
          for (const key in transform) {
            result.push({
              category: key,
              details: transform[key].sort((a, b) => {
                if (!a || !b) return 10000
                const semesterPartsA = a.T.split('-') // 分割字符串得到年份和学期
                const semesterPartsB = b.T.split('-')
                if (!semesterPartsA[0] || !semesterPartsB[0]) return 10000

                // 先比较年份
                if (semesterPartsA[0] !== semesterPartsB[0]) {
                  return semesterPartsA[0] - semesterPartsB[0] // 年份不同的情况下，按年份数字排序
                }

                // 年份相同，则比较学期编号，考虑可能的“上”、“下”学期标记
                const semesterIndexA = parseInt(semesterPartsA[2].replace('上', '1').replace('下', '2'), 10)
                const semesterIndexB = parseInt(semesterPartsB[2].replace('上', '1').replace('下', '2'), 10)

                return semesterIndexA - semesterIndexB // 按学期编号排序
              }),
              need: dictCredit[key][0],
              has: dictCredit[key][1],
            })
          }

          // 补充（有些类型的课程还没用修读明细）
          for (const key in dictCredit) {
            if (result.findIndex((e) => e.category === key) === -1) {
              result.push({
                category: key,
                details: [],
                need: dictCredit[key][0],
                has: dictCredit[key][1],
              })
            }
          }

          // console.log('result', result)
          return result
        }
        return result
      } catch (err) {
        console.log(err)
        throw err
      }
    }
    return result
  }

  /**
   * * 创新学分、素拓分、第二课堂分（成绩证书）
   * @return {Array} *
   */
  async extra() {
    const Cookie = this.ctx.state.Cookie
    const apiUrl = `${this.ctx.state.baseUrl}/jsxsd/xsxkjs/xkjscjzscx.do`
    const res = await this.ctx.curl(apiUrl, {
      method: 'POST',
      headers: {
        Cookie,
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
      },
      data: {
        sqnd: '',
        jsjb: '',
      },
      timeout: 10000,
    })

    // 序号 参赛年度 项目名称 承办学院 竞赛类别 竞赛级别 获奖级别 获奖金额 操作
    const header = ['参赛年度', '项目名称', '承办学院', '竞赛类别', '竞赛级别', '获奖级别', '获奖金额']

    if (res.status === 200) {
      try {
        const tableList = tableToList(res.data.toString(), '#dataList')
        console.log('tableList', tableList)
        const columnNeed = [1, 2, 3, 4, 5, 6, 7]
        if (tableList.length === 0 || tableList[1][0] === '未查询到数据') return { table: {}, header }
        const info = []
        for (let i = 1; i < tableList.length; i++) {
          const tem = []
          columnNeed.forEach((idx) => (tem.push(tableList[i][idx])))
          info.push(tem)
        }
        return { table: info, header, has: 0 }
      } catch (err) {
        console.log('err', err)
        throw err
      }
    }
    return { table: [], header, has: 0 }
  }
}
